package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SecKillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.constant.RedisConst;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.result.Result;
import com.atguigu.gmall.result.ResultCodeEnum;
import com.atguigu.gmall.util.MD5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
@SuppressWarnings("all")
public class SecKillGoodsServiceImpl implements SecKillGoodsService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    /**
     * 查询秒杀列表
     * @return
     */
    @Override
    public List<SeckillGoods> findAll() {
        // List<SeckillGoods> values = redisTemplate.opsForHash().values(RedisConst.SECKILL_GOODS);
        // 或
        List values = redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).values();
        return values;
    }

    /**
     * 获取秒杀商品详情
     * @param skuId
     * @return
     */
    @Override
    public SeckillGoods getSeckillGoods(Long skuId) {
        return (SeckillGoods) this.redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).get(skuId.toString());
    }

    /**
     * 抢单
     * @param userId
     * @param skuId
     */
    @Override
    public void seckillOrder(String userId, Long skuId) {
        // 校验状态位
        String status = (String) CacheHelper.get(skuId.toString());
        if ("0".equals(status)) {
            return;
        }

        // 校验是否下过单
        Boolean flag = this.redisTemplate.opsForValue().setIfAbsent(RedisConst.SECKILL_USER + userId, skuId.toString());
        if (!flag) {
            return;
        }

        // 校验库存
        String stockSkuId = (String) this.redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).rightPop();
        if (StringUtils.isEmpty(stockSkuId)) {
            this.redisTemplate.convertAndSend("seckillPush",skuId+":0");
            return;
        }

        // 生成临时订单信息存储到redis
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userId);
        orderRecode.setNum(1);
        SeckillGoods seckillGoods = this.getSeckillGoods(skuId);
        orderRecode.setSeckillGoods(seckillGoods);
        // 订单码
        orderRecode.setOrderStr(MD5.encrypt(userId+skuId));

        // 存储
        redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).put(userId,orderRecode);

        // 更新库存量
        this.updateStockCount(skuId);
    }

    /**
     * 查询秒杀抢购状态
     * @param skuId
     * @param userId
     * @return
     */
    @Override
    public Result checkOrder(Long skuId, String userId) {
        // 查询用户是否有记录
        Boolean isExist = this.redisTemplate.hasKey(RedisConst.SECKILL_USER + userId);
        // 判断
        if (isExist) {
            // 尝试获取用户的订单--临时订单：说明用户还没有支付
            OrderRecode orderRecode = (OrderRecode) this.redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).get(userId);
            if (orderRecode != null) {
                // 说明用户还没有支付
                return Result.build(orderRecode,ResultCodeEnum.SECKILL_SUCCESS);
            }

            // 查询总订单--SECKILL_ORDERS_USERS
            Boolean aBoolean = this.redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).hasKey(userId);
            if (aBoolean) {
                // seckill:orders:users  userId  orderId
                return Result.build(orderRecode,ResultCodeEnum.SECKILL_ORDER_SUCCESS);
            }
        }

        String status = (String) CacheHelper.get(skuId.toString());
        if ("0".equals(status)) {
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }

        return Result.build(null, ResultCodeEnum.SECKILL_RUN);
    }

    /**
     * 修改mysql，修改redis
     * @param skuId
     */
    private void updateStockCount(Long skuId) {
        // 获取锁对象
        Lock lock = new ReentrantLock();
        // 加锁
        lock.lock();

        try {
            // 获取库存
            Long stockKey = this.redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).size();

            // 获取当前商品的信息
            SeckillGoods seckillGoods = this.getSeckillGoods(skuId);
            // 设置库存
            seckillGoods.setStockCount(stockKey.intValue());

            // 修改数据库mysql，可以实时更新mysql，也可以最后更新mysql，也可以stockKey%2==0更新mysql
            if (stockKey == 0) {
                this.seckillGoodsMapper.updateById(seckillGoods);
            }
            // this.seckillGoodsMapper.updateById(seckillGoods);

            // 更新缓存
            this.redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).put(skuId.toString(),seckillGoods);
        } finally {
            lock.unlock();
        }
    }
}
